<?php
/**
 * Utility for savig system configuration.
 *
 * @author Martin "DevelX" Jurča
 * @version 2009-07-05
 */
class ConfigStorage {
    public static function save($config, $root = false) {
        if (!self::check($config)) {
            return false;
        }
        if ($root === false) {
            $root = Config::ROOT;
        }
        if (!is_writable($root . ($root == '' ? '' : '/') . 'config.php')) {
            FTP::chmod('/config.php');
        }
        
        $file = @fopen($root . ($root == '' ? '' : '/') . 'config.php', 'w');
        if (!is_resource($file)) {
            return false;
        }
        @flock($file, LOCK_EX);
        self::writeHeader($file);
        self::writeConfig($file, $config);
        self::writeFooter($file);
        @flock($file, LOCK_UN);
        return @fclose($file);
    }

    public static function applyChanges($changes) {
        $config = array('AUTODETECT_SESSION_CHARSET' =>
                Config::AUTODETECT_SESSION_CHARSET,
                'AUTODETECT_SESSION_LANG' => Config::AUTODETECT_SESSION_LANG,
                'CACHE_DB_TIMEOUT' => Config::CACHE_DB_TIMEOUT,
                'CACHE_IMAGE_TIMEOUT' => Config::CACHE_IMAGE_TIMEOUT,
                'CACHE_OUTPUT_TIMEOUT' => Config::CACHE_OUTPUT_TIMEOUT,
                'DATABASE_ACCESS' => Config::DATABASE_ACCESS,
                'DATABASE_DRIVER' => Config::DATABASE_DRIVER,
                'DEFAULT_CHARSET' => Config::DEFAULT_CHARSET, 'DEFAULT_LANG' =>
                Config::DEFAULT_LANG, 'DOMAIN_NAME' => Config::DOMAIN_NAME,
                'FTP_DIRECTORY' => Config::FTP_DIRECTORY, 'FTP_HOST' =>
                Config::FTP_HOST, 'FTP_LOGIN' => Config::FTP_LOGIN,
                'FTP_PASSWORD' => Config::FTP_PASSWORD, 'IMAGE_BACKGROUND_B' =>
                Config::IMAGE_BACKGROUND_B, 'IMAGE_BACKGROUND_G' =>
                Config::IMAGE_BACKGROUND_G, 'IMAGE_BACKGROUND_R' =>
                Config::IMAGE_BACKGROUND_R, 'IMAGE_QUALITY' =>
                Config::IMAGE_QUALITY, 'INSTALLED' => Config::INSTALLED,
                'MAX_CACHE_SIZE' => Config::MAX_CACHE_SIZE, 'ROOT' =>
                Config::ROOT, 'TIMEZONE' => Config::TIMEZONE, 'WEB_DIR' =>
                Config::WEB_DIR);
        foreach ($config as $name => &$value) {
            if (isset($changes[$name])) {
                $value = $changes[$name];
            }
        }
        return self::save($config);
    }

    /**
     * Writes configuration to the file.
     *
     * @param resource $file File handler resource of the open config file.
     * @param Array $config Configuration array.
     */
    private static function writeConfig($file, $config) {
        $cfg = '';
        foreach ($config as $name => $value) {
            if (is_bool($value)) {
                if ($value) {
                    $value = 'true';
                } else {
                    $value = 'false';
                }
            } elseif (is_string($value)) {
                $value = "'$value'";
            }
            $cfg .= "    const $name = $value;\n";
        }
        @fwrite($file, $cfg);
    }

    /**
     * Writes footer of the configuration file.
     *
     * @param resource $file File handler resource of the open config file.
     */
    private static function writeFooter($file) {
        $footer = "}\n?>\n";
        @fwrite($file, $footer);
    }

    /**
     * Writes header of the configuration file.
     *
     * @param resource $file File handler resource of the open config file.
     */
    private static function writeHeader($file) {
        $header = "<?php\n/**\n * Configuration\n" .
                " * Generated by ConfigStorage utility\n *\n" .
                " * @version " . @date("Y-m-d") . "\n */\nclass Config {\n";
        @fwrite($file, $header);
    }

    /**
     * Check whether the given configuration array is valid or not - whether
     * it contains only allowed keys and no key is missing.
     *
     * @param Array $config Configuration array to check.
     * @return boolean True if the configuration file is valid, false
     *         otherwise.
     */
    private static function check($config) {
        $props = array('INSTALLED', 'WEB_DIR', 'ROOT',
                'DOMAIN_NAME', 'TIMEZONE', 'DEFAULT_LANG', 'DEFAULT_CHARSET',
                'AUTODETECT_SESSION_LANG', 'AUTODETECT_SESSION_CHARSET',
                'DATABASE_ACCESS', 'DATABASE_DRIVER', 'FTP_HOST', 'FTP_LOGIN',
                'FTP_PASSWORD', 'FTP_DIRECTORY', 'IMAGE_QUALITY',
                'IMAGE_BACKGROUND_R', 'IMAGE_BACKGROUND_G',
                'IMAGE_BACKGROUND_B', 'MAX_CACHE_SIZE', 'CACHE_DB_TIMEOUT',
                'CACHE_OUTPUT_TIMEOUT', 'CACHE_IMAGE_TIMEOUT', 'BUGREPORT');
        $keys = array_keys($config);
        foreach ($keys as $key) {
            if (in_array($key, $props) === false) {
                return false;
            }
        }
        foreach ($props as $prop) {
            if (!isset($config[$prop])) {
                return false;
            }
        }
        return self::checkTypes($config);
    }

    /**
     * Check whether the values of given configuration array has correct
     * types.
     *
     * @param Array $config Configuration array to check.
     * @return boolean True it the values of the array has correct value types.
     */
    private static function checkTypes($config) {
        $bools = array('INSTALLED', 'AUTODETECT_SESSION_LANG',
                'AUTODETECT_SESSION_CHARSET');
        $ints = array('IMAGE_QUALITY', 'IMAGE_BACKGROUND_R',
                'IMAGE_BACKGROUND_G', 'IMAGE_BACKGROUND_B', 'MAX_CACHE_SIZE',
                'CACHE_DB_TIMEOUT', 'CACHE_OUTPUT_TIMEOUT',
                'CACHE_IMAGE_TIMEOUT');

        foreach ($bools as $name) {
            if (!is_bool($config[$name])) {
                return false;
            }
        }
        foreach ($ints as $name) {
            if (!is_int($config[$name])) {
                return false;
            }
        }
        foreach ($config as $name => $value) {
            if (!in_array($name, $bools) && !in_array($name, $ints) &&
                    !is_string($value)) {
                return false;
            }
        }
        return true;
    }
}
?>
